package org.example.service;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.example.domain.*;
import org.example.utils.HttpResult;
import org.example.utils.HttpUtils;
import org.example.utils.WxAccessTokenClient;
import org.example.utils.XmlBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;

import static org.example.config.Constant.*;

@Service
@Slf4j
public class ChatService {

    private static final ConcurrentHashMap<String, User> map = new ConcurrentHashMap<>();

    private static final ConcurrentHashMap<String, List<WxOutputMessage>> mapMsg = new ConcurrentHashMap<>();

    private static volatile boolean runningFlag = false;

    @Autowired
    WxAccessTokenClient wxAccessTokenClient;

    @Autowired
    Executor executor;

    @Value("${proxy.flag:false}")
    String usingProxy;
    @Value("${proxy.ip:127.0.0.1}")
    String proxyIp;

    @Value("${proxy.port:10809}")
    int proxyPort;

    @Value(("${chatgptToken: }"))
    String chatgptToken;

    @Value("${wxToken: }")
    String token;

    @Value("${wxEncodingAESKey: }")
    String wxEncodingAESKey;

    public void receiveFromWx(String body, HttpServletResponse response) throws IOException {
        WxInputMessage input = (WxInputMessage) XmlBuilder.xmlStrToObject(WxInputMessage.class, body);
        if (input == null) {
            log.info("数据解析失败！");
            response.getWriter().println("数据解析失败!");
            return;
        }
        WxOutputMessage returnMsg = new WxOutputMessage();
        returnMsg.setCreateTime(System.currentTimeMillis());
        returnMsg.setMsgType("text");
        returnMsg.setToUserName(input.getFromUserName());
        returnMsg.setFromUserName(input.getToUserName());
        returnMsg.setMsgId(input.getMsgId());
        log.info(input.toString());
        if (!"text".equals(input.getMsgType())) {
            log.info("不支持的消息类型！");
            returnMsg.setContent("不支持的消息类型，目前只支持text");
            response.getWriter().println(XmlBuilder.objectToXmlStr(returnMsg));
            return;
        }
        if (COMMAND_CLEAR.equals(input.getContent())) {
            log.info("清除上下文消息！");
            User remove = map.remove(input.getFromUserName());
            int count = 0;
            if (remove != null && remove.getMessages() != null) {
                count = remove.getMessages().size();
            }
            returnMsg.setContent("清除上下文消息成功，共" + count + "条");
            response.getWriter().println(XmlBuilder.objectToXmlStr(returnMsg));
            return;
        }
        if (COMMAND_GET.equals(input.getContent())) {
            //获取消息
            log.info("获取消息！" + input.getMsgId());
            List<WxOutputMessage> oldList = mapMsg.get(input.getFromUserName());
            if (CollectionUtils.isEmpty(oldList)) {
                returnMsg.setContent("目前暂无消息");
                response.getWriter().println(XmlBuilder.objectToXmlStr(returnMsg));
                return;
            }
            StringBuilder sb = new StringBuilder();
            synchronized (this) {
                for (int i = 0; i < oldList.size(); i++) {
                    if (i != 0) {
                        sb.append("\n");
                    }
                    sb.append(oldList.get(i).getContent());
                }
                mapMsg.remove(input.getFromUserName());
            }
            returnMsg.setContent(sb.toString());
            response.getWriter().println(XmlBuilder.objectToXmlStr(returnMsg));
            return;
        }
        if (!CollectionUtils.isEmpty(mapMsg.get(input.getFromUserName()))) {
            log.info("上一次消息没有获取！" + input.getFromUserName());
            returnMsg.setContent("上一次回复消息还未获取，请先用get命令获取");
            response.getWriter().println(XmlBuilder.objectToXmlStr(returnMsg));
            return;
        }
        if (runningFlag) {
            //限流
            log.info("限流！" + input.getFromUserName());
            returnMsg.setContent("限流！");
            response.getWriter().println(XmlBuilder.objectToXmlStr(returnMsg));
            return;
        }
        try {
            executor.execute(() -> {
                synchronized (this) {
                    try {
                        runningFlag = true;
                        ChatResponse result = chatgptApi1(WxRequest.builder().openID(input.getFromUserName()).content(input.getContent()).build());
                        //发送微信客服消息
                        StringBuilder bu = new StringBuilder();
                        List<ChatResponse.Choice> list = result.getChoices();
                        for (ChatResponse.Choice choice : list) {
                            bu.append(choice.getMessage().getContent());
                        }
                        //这里需要直接回复消息
                        returnMsg.setContent(bu.toString());
                        List<WxOutputMessage> msgList = mapMsg.getOrDefault(input.getFromUserName(), new ArrayList<>());
                        msgList.add(returnMsg);
                        mapMsg.put(input.getFromUserName(), msgList);
                    } catch (Exception e) {
                        log.error("未知错误", e);
                    } finally {
                        runningFlag = false;
                    }
                }
            });
        } catch (Exception e) {
            log.error("线程池报错", e);
            returnMsg.setContent("限流！！");
            response.getWriter().println(XmlBuilder.objectToXmlStr(returnMsg));
            return;
        }
        returnMsg.setContent("请先等待5-30秒，再用get命令获取回答");
        response.getWriter().println(XmlBuilder.objectToXmlStr(returnMsg));
    }

    public synchronized ChatResponse chatgptApi1(WxRequest request) {
        String openID = request.getOpenID();
        User user = map.get(openID);
        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setRole(ChatMessage.ROLE_USER);
        chatMessage.setContent(request.getContent());
        if (user == null) {
            user = new User();
            user.setUniCode(openID);
            map.put(openID, user);
        }
        user.getMessages().add(chatMessage);
        ChatRequest chatRequest = new ChatRequest();
        chatRequest.setModel(GPT_3_5_TURBO);
        chatRequest.setMessages(user.getMessages());
        Proxy proxy = null;
        if (usingProxy.equals("true")) {
            proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyIp, proxyPort));
        }
        Map<String, String> reqHeaderApi1 = new HashMap<>();
        reqHeaderApi1.put("Authorization", "Bearer " + chatgptToken);
        HttpResult<ChatResponse> httpResult = HttpUtils.postApplicationJson(API_URL1, reqHeaderApi1, chatRequest, ChatResponse.class, proxy);
        if (httpResult.getStatusCode() != 200 || httpResult.getResult() == null || CollectionUtils.isEmpty(httpResult.getResult().getChoices())) {
            user.clearMessages();
            log.info("报错清除历史消息:" + openID);
            return null;
        }
        //保存此轮回复
        ChatResponse result = httpResult.getResult();
        List<ChatResponse.Choice> choices = result.getChoices();
        if (!CollectionUtils.isEmpty(choices)) {
            for (ChatResponse.Choice choice : choices) {
                ChatMessage message = choice.getMessage();
                user.getMessages().add(message);
            }
        }
        return result;
    }

    public void tokenCheck(HttpServletRequest request, HttpServletResponse response) throws IOException {
        /*
         * 验证消息的确来自微信服务器
         * 1）将token、timestamp、nonce三个参数进行字典序排序
         * 2）将三个参数字符串拼接成一个字符串进行sha1加密
         * 3）开发者获得加密后的字符串可与signature对比，标识该请求来源于微信
         * */
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        log.info("signature=" + signature + ",timestamp=" + timestamp + ",nonce=" + nonce + ",echostr=" + echostr);
        String[] arr = {token, timestamp, nonce};
        Arrays.sort(arr);
        StringBuilder sb = new StringBuilder();
        for (String a : arr) {
            sb.append(a);
        }
        String sha1Msg = DigestUtils.sha1Hex(sb.toString().getBytes());
        if (signature.equals(sha1Msg)) {
            log.info("验证成功！");
            response.getWriter().println(echostr);
        }
    }

}
